from manimlib import *


class TestScene(Scene):
    def construct(self):
        def create_bezier(n, dot_list):
            allDotGup = VGroup()
            alLineGup = VGroup()
            for i in range(1, n + 1):
                dg = VGroup()
                for j in range(n - i, -1, -1):
                    dg.add(Dot(dot_list[j]))
                allDotGup.add(dg)
            for i in range(1, n):
                lg = VGroup()
                for j in range(n - i, 0, -1):
                    lg.add(Line(dot_list[j], dot_list[j - 1]))
                alLineGup.add(lg)
            allDotGup.add(allDotGup[0].copy())
            alLineGup.add(alLineGup[0].copy())
            return allDotGup, alLineGup

        def anim(a, alpha):
            n = len(a) - 1
            for i in range(n - 1):
                for j in range(n - i - 1):
                    a[i + 1][j].add_updater(
                        lambda x: x.move_to(
                            interpolate(
                                a[i][j].get_center(),
                                a[i][j + 1].get_center(),
                                alpha,
                            )
                        )
                    )

        dot_lst = [
            np.array([-3, -3, 0]),
            np.array([-3, 3, 0]),
            np.array([3, 3, 0]),
            np.array([3, -3, 0]),
        ]
        dot, line = create_bezier(4, dot_lst)
        dot[3][0].move_to(np.array([3, -3, 0]))
        k = VGroup(dot, line)

        def sync_line(lg):
            n = len(lg)
            for i in range(n):
                for j in range(n - i - 1):
                    lg[i][j].put_start_and_end_on(
                        k[0][i][j].get_center(), k[0][i][j + 1].get_center()
                    )

        k[1].add_updater(sync_line)
        path = TracedPath(k[0][3][0].get_center, stroke_color=YELLOW, stroke_width=6)
        self.add(k, path)
        self.play(UpdateFromAlphaFunc(k[0], anim), run_time=8)


class Envelope(Scene):
    def construct(self):
        cir_r = 3.5
        color_dict = [RED, ORANGE, GOLD, YELLOW, GREEN, TEAL, BLUE, PURPLE]
        cir = Circle(radius=cir_r, stroke_width=1)
        t = ValueTracker(0)
        lg = VGroup()
        pos = []
        num = 60
        for i in range(num):
            lg.add(Line(stroke_width=1))
            pos.append(
                np.array(
                    [cir_r * np.cos(i * TAU / num), cir_r * np.sin(i * TAU / num), 0]
                )
            )

        def anim(obj):
            for i in range(num):
                tar = np.array(
                    [
                        cir_r * np.cos(t.get_value() * i * TAU / num),
                        cir_r * np.sin(t.get_value() * i * TAU / num),
                        0,
                    ]
                )
                if abs(get_norm(pos[i] - tar)) > 1e-6:
                    obj[i].put_start_and_end_on(
                        pos[i],
                        tar,
                    )
                else:
                    obj[i].move_to(DOWN * 10)
            obj.set_color(color_dict)

        lg.add_updater(anim)
        self.add(cir, lg)
        self.play(t.set_value, 200, run_time=100, rate_func=linear)


class TestTex(Scene):
    def construct(self):
        mob = NumberPlane()
        family = mob.get_family()
        print(family[:4])
        for ind, each in enumerate(family[:4]):
            print(f"family[{ind}].get_points(): ", each.get_points())